﻿using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using LINQPad.OpenAccess.Infrastructure;
using LINQPad.OpenAccess.UI.Services;
using LINQPad.OpenAccess.UI.ViewModel;

namespace LINQPad.OpenAccess.UI.View
{
    /// <summary>
    /// Host for connection setting views.
    /// </summary>
    public partial class ConnectionSettingsViewHost : Control
    {
        #region Protected

        #region - Functions

        /// <summary>
        /// Accepts the connection settings.
        /// </summary>
        /// <param name="settings">The settings.</param>
        protected virtual void AcceptConnectionSettings( IConnectionSettingsViewModel settings )
        {

        }
        /// <summary>
        /// Accepts the view.
        /// </summary>
        /// <param name="view">The view.</param>
        protected virtual void AcceptView( FrameworkElement view )
        {
            view.SetBinding( ContentControl.DataContextProperty, new Binding { Path = new PropertyPath( ConnectionSettingsProperty ), Source = this } );
        }
        /// <summary>
        /// Releases the connection settings.
        /// </summary>
        /// <param name="settings">The settings.</param>
        protected virtual void ReleaseConnectionSettings( IConnectionSettingsViewModel settings )
        {
        }
        /// <summary>
        /// Releases the view.
        /// </summary>
        /// <param name="view">The view.</param>
        protected virtual void ReleaseView( FrameworkElement view )
        {
            BindingOperations.ClearBinding( view, ContentControl.DataContextProperty );
        }
        /// <summary>
        /// Resets the view factory.
        /// </summary>
        protected virtual void ResetViewFactory( )
        {
            this.ViewFactory = ServiceLocator.Current.Get<IConnectionSettingsViewFactory>( );
        }
        /// <summary>
        /// Called when the connection settings property has changed.
        /// </summary>
        /// <param name="newSettings">The new settings.</param>
        /// <param name="oldSettings">The old settings.</param>
        protected virtual void OnConnectionSettingsChanged( IConnectionSettingsViewModel newSettings, IConnectionSettingsViewModel oldSettings )
        {
            if ( oldSettings != null )
                this.ReleaseConnectionSettings( oldSettings );
            if ( newSettings == null )
                this.View = null;
            else
            {
                this.AcceptConnectionSettings( newSettings );

                // view creation required ?
                if ( oldSettings == null || oldSettings.GetType( ) != newSettings.GetType( ) )
                    this.View = this.ViewFactory == null
                                    ? null
                                    : this.ViewFactory.CreateConnectionSettingsView( newSettings );
            }
        }
        /// <summary>
        /// Called when the view factory property has changed.
        /// </summary>
        /// <param name="newFactory">The new factory.</param>
        /// <param name="oldFactory">The old factory.</param>
        protected virtual void OnViewFactoryChanged( IConnectionSettingsViewFactory newFactory, IConnectionSettingsViewFactory oldFactory )
        {
            this.View = null;

            if ( newFactory == null )
            {
                this.ResetViewFactory( );
                return;
            }

            if ( this.ConnectionSettings != null )
                this.View = newFactory.CreateConnectionSettingsView( this.ConnectionSettings );
        }
        /// <summary>
        /// Called when the view property has changed.
        /// </summary>
        /// <param name="newView">The new view.</param>
        /// <param name="oldView">The old view.</param>
        protected virtual void OnViewChanged( FrameworkElement newView, FrameworkElement oldView )
        {
            if ( oldView != null )
                this.ReleaseView( oldView );
            if ( newView != null )
                this.AcceptView( newView );
        }

        #endregion

        #endregion

        #region Public

        #region - Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="ConnectionSettingsViewHost" /> class.
        /// </summary>
        public ConnectionSettingsViewHost( )
        {
            if ( DesignerProperties.GetIsInDesignMode( this ) )
                this.View = new TextBlock { Text = "<placeholder for rendered ConnectionSettingsView />" };
            else
                this.ResetViewFactory( );
        }

        #endregion

        #region - Properties

        /// <summary>
        /// Gets or sets the connection settings.
        /// </summary>
        /// <value>
        /// The connection settings.
        /// </value>
        public IConnectionSettingsViewModel ConnectionSettings
        {
            get { return ( IConnectionSettingsViewModel ) GetValue( ConnectionSettingsProperty ); }
            set { SetValue( ConnectionSettingsProperty, value ); }
        }
        /// <summary>
        /// Gets the view.
        /// </summary>
        /// <value>
        /// The view.
        /// </value>
        public FrameworkElement View
        {
            get { return ( FrameworkElement ) GetValue( ViewProperty ); }
            private set { SetValue( _ViewPropertyKey, value ); }
        }
        /// <summary>
        /// Gets or sets the view factory.
        /// </summary>
        /// <value>
        /// The view factory.
        /// </value>
        public IConnectionSettingsViewFactory ViewFactory
        {
            get { return ( IConnectionSettingsViewFactory ) GetValue( ViewFactoryProperty ); }
            set { SetValue( ViewFactoryProperty, value ); }
        }

        #endregion

        #endregion
    }
}
